package com.blog4j.article.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog4j.api.client.FeignUser;
import com.blog4j.api.vo.UserInfoVo;
import com.blog4j.article.component.AsyncService;
import com.blog4j.article.entity.ArticleEntity;
import com.blog4j.article.entity.CategoryEntity;
import com.blog4j.article.entity.CategoryLabelRelEntity;
import com.blog4j.article.entity.LabelEntity;
import com.blog4j.article.mapper.ArticleMapper;
import com.blog4j.article.mapper.CategoryLabelRelMapper;
import com.blog4j.article.mapper.CategoryMapper;
import com.blog4j.article.mapper.LabelMapper;
import com.blog4j.article.service.LabelService;
import com.blog4j.article.vo.req.CreateLabelReqVo;
import com.blog4j.article.vo.req.DeleteLabelReqVo;
import com.blog4j.article.vo.req.EditLabelReqVo;
import com.blog4j.article.vo.req.LabelListReqVo;
import com.blog4j.common.constants.CommonConstant;
import com.blog4j.common.enums.CategoryAndLabelStatusEnum;
import com.blog4j.common.enums.ErrorEnum;
import com.blog4j.common.exception.Blog4jException;
import com.blog4j.common.utils.CommonUtil;
import com.blog4j.common.utils.IdGeneratorSnowflakeUtil;
import com.github.pagehelper.PageHelper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 98k灬
 * @version v1.0.0
 * @Description : 功能描述
 * @Create on : 2024/7/2 21:18
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class LabelServiceImpl extends ServiceImpl<LabelMapper, LabelEntity> implements LabelService {
    private final CategoryMapper categoryMapper;
    private final CategoryLabelRelMapper categoryLabelRelMapper;
    private final FeignUser feignUser;
    private final ArticleMapper articleMapper;
    private final AsyncService asyncService;

    /**
     * 根据分类ID查询标签信息列表
     *
     * @param categoryId 分类ID
     * @return 标签信息列表
     */
    @Override
    public List<LabelEntity> getByCategoryId(String categoryId) {
        CategoryEntity category = categoryMapper.selectById(categoryId);
        if (Objects.isNull(category)) {
            log.error("Category is null .");
            throw new Blog4jException(ErrorEnum.CATEGORY_INFO_EMPTY_ERROR);
        }

        LambdaQueryWrapper<CategoryLabelRelEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CategoryLabelRelEntity::getCategoryId, categoryId);
        List<CategoryLabelRelEntity> relList = categoryLabelRelMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(relList)) {
            return null;
        }

        Set<String> labelIdSet = relList.stream().map(CategoryLabelRelEntity::getLabelId).collect(Collectors.toSet());
        List<LabelEntity> labelList = this.baseMapper.selectBatchIds(labelIdSet);
        return labelList.stream().filter(item ->
                Objects.equals(CategoryAndLabelStatusEnum.NORMAL.getCode(), item.getStatus()))
                .collect(Collectors.toList());
    }

    /**
     * 根据创建者ID获取标签列表
     *
     * @return 标签列表
     */
    @Override
    public List<LabelEntity> getListByCreaterId() {
        LambdaQueryWrapper<LabelEntity> wrapper = new LambdaQueryWrapper<LabelEntity>()
                .eq(LabelEntity::getCreater, StpUtil.getLoginIdAsString())
                .eq(LabelEntity::getStatus, CategoryAndLabelStatusEnum.NORMAL.getCode());
        return this.baseMapper.selectList(wrapper);
    }

    /**
     * 标签列表查询
     *
     * @param reqVo 请求信息
     * @return 标签列表
     */
    @Override
    public List<LabelEntity> getLabelList(LabelListReqVo reqVo) {
        Integer pageNo = reqVo.getPageNo();
        Integer pageSize = reqVo.getPageSize();
        String labelName = reqVo.getLabelName();
        Integer status = reqVo.getStatus();
        String scope = reqVo.getScope();

        LambdaQueryWrapper<LabelEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(LabelEntity::getCreateTime);
        if (Objects.nonNull(status)) {
            this.checkLabelStatus(status);
            wrapper.eq(LabelEntity::getStatus, status);
        }

        if (StringUtils.equals(scope, CommonConstant.SELF)) {
            wrapper.eq(LabelEntity::getCreater, StpUtil.getLoginIdAsString());
        }

        if (StringUtils.isNotBlank(labelName)) {
            wrapper.like(LabelEntity::getLabelName, labelName);
        }
        PageHelper.startPage(pageNo, pageSize);
        return this.baseMapper.selectList(wrapper);
    }

    /**
     * 编辑标签信息
     *
     * @param reqVo 请求信息
     */
    @Override
    public void edit(EditLabelReqVo reqVo) {
        Integer status = reqVo.getStatus();
        String labelId = reqVo.getLabelId();
        String labelName = reqVo.getLabelName();
        this.checkLabelStatus(status);

        LabelEntity label = this.baseMapper.selectById(labelId);
        if (Objects.isNull(label)) {
            throw new Blog4jException(ErrorEnum.LABEL_INFO_EMPTY_ERROR);
        }

        LambdaQueryWrapper<LabelEntity> wrapper = new LambdaQueryWrapper<LabelEntity>()
                .ne(LabelEntity::getCreater, label.getCreater())
                .eq(LabelEntity::getLabelName, reqVo.getLabelName());
        if (this.baseMapper.selectCount(wrapper) > 0) {
            throw new Blog4jException(ErrorEnum.LABEL_NAME_REPEAT_ERROR);
        }

        LambdaQueryWrapper<LabelEntity> wrapper1 = new LambdaQueryWrapper<LabelEntity>()
                .ne(LabelEntity::getCreater, label.getCreater())
                .eq(LabelEntity::getLabelCode, reqVo.getLabelCode());
        if (this.baseMapper.selectCount(wrapper1) > 0) {
            throw new Blog4jException(ErrorEnum.LABEL_CODE_REPEAT_ERROR);
        }

        LabelEntity labelEntity = new LabelEntity();
        BeanUtils.copyProperties(reqVo, labelEntity);
        labelEntity.setUpdateTime(CommonUtil.getCurrentDateTime());
        this.baseMapper.updateById(labelEntity);

        // 异步更新文章信息中的标签信息
        if (!StringUtils.equals(labelName, label.getLabelName())) {
            asyncService.updateArticleLabelName(labelId, labelName);
        }
    }

    /**
     * 创建标签信息
     *
     * @param reqVo 请求信息
     */
    @Override
    public void create(CreateLabelReqVo reqVo) {
        Integer status = reqVo.getStatus();
        this.checkLabelStatus(status);
        String userId = StpUtil.getLoginIdAsString();
        UserInfoVo user = feignUser.getUserInfoByUserId(userId);

        LambdaQueryWrapper<LabelEntity> wrapper = new LambdaQueryWrapper<LabelEntity>()
                .eq(LabelEntity::getCreater, userId)
                .eq(LabelEntity::getLabelName, reqVo.getLabelName());
        if (this.baseMapper.selectCount(wrapper) > 0) {
            throw new Blog4jException(ErrorEnum.LABEL_NAME_REPEAT_ERROR);
        }

        LambdaQueryWrapper<LabelEntity> wrapper1 = new LambdaQueryWrapper<LabelEntity>()
                .eq(LabelEntity::getCreater, userId)
                .eq(LabelEntity::getLabelCode, reqVo.getLabelCode());
        if (this.baseMapper.selectCount(wrapper1) > 0) {
            throw new Blog4jException(ErrorEnum.LABEL_CODE_REPEAT_ERROR);
        }

        LabelEntity label = LabelEntity.builder()
                .labelId(IdGeneratorSnowflakeUtil.snowflakeId())
                .labelName(reqVo.getLabelName())
                .labelCode(reqVo.getLabelCode())
                .status(reqVo.getStatus())
                .creater(userId)
                .createrName(user.getUserName())
                .updateTime(CommonUtil.getCurrentDateTime())
                .createTime(CommonUtil.getCurrentDateTime())
                .build();
        this.baseMapper.insert(label);
    }

    /**
     * 删除标签信息
     *
     * @param reqVo 请求信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(DeleteLabelReqVo reqVo) {
        List<String> labelIds = reqVo.getLabelIds();
        this.baseMapper.deleteBatchIds(labelIds);

        LambdaQueryWrapper<ArticleEntity> queryWrapper = new LambdaQueryWrapper<ArticleEntity>()
                .in(ArticleEntity::getLabelId, labelIds);
        Integer count = articleMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new Blog4jException(ErrorEnum.LABEL_BIND_ARTICLE_ERROR);
        }

        // 删除分类与标签的关联关系表
        LambdaQueryWrapper<CategoryLabelRelEntity> wrapper = new LambdaQueryWrapper<CategoryLabelRelEntity>()
                .in(CategoryLabelRelEntity::getLabelId, labelIds);
        categoryLabelRelMapper.delete(wrapper);
    }

    private void checkLabelStatus(Integer status) {
        if (!Objects.equals(status, CategoryAndLabelStatusEnum.NORMAL.getCode()) &&
                !Objects.equals(status, CategoryAndLabelStatusEnum.DISABLE.getCode())) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
    }
}
